﻿using System;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using Legend.Mesh;
using Legend.Object;
using Legend.Component.Interface;
using Microsoft.Xna.Framework.Input;
using System.Collections.Generic;

namespace Legend.Component.Hero
{
    public class KeyboardProcessor : IInputProcessor
    {
        private float maxspeed = 100;
        private float acceleration = 0;
        private Vector3 lastVelocity = Vector3.Zero;
//        private BoundingBox movableBoundingBox;
        private Ray[] XRays = new Ray[3];
        private Ray[] YRays = new Ray[5];
        private bool fireButtonUp = true;

        public KeyboardProcessor()
        {
        }

        public float MaxSpeed
        {
            get { return maxspeed; }
            set { maxspeed = value; }
        }
        public float Acceleration
        {
            get { return acceleration; }
            set { acceleration = value; }
        }

        //public BoundingBox MovingBoundary
        //{
        //    get { return movableBoundingBox; }
        //    set { movableBoundingBox = value; }
        //}

        public override void ProcessInput(GameTime gameTime, List<ICollision> blockList)
        {
            IMovement movement = Owner.FindComponent<IMovement>();
            if (movement == null)
            {
                throw new InvalidOperationException("This GameObject does not have IMovement component");
            }

            Vector3 direction = Vector3.Zero;
            Vector3 RightUp = new Vector3(30, 30, 30);
            Vector3 RightDown = new Vector3(30, -30, 30);
            Vector3 LeftUp = new Vector3(-30, 30, 30);
            Vector3 LeftDown = new Vector3(-30, -30, 30);

            if (Keyboard.GetState().IsKeyDown(Keys.Left))
            {
                direction.X -= 1f;
                XRays[0] = new Ray(movement.Position + LeftUp, new Vector3(-1, 0, 0));
                XRays[1] = new Ray(movement.Position + LeftDown, new Vector3(-1, 0, 0));
                XRays[2] = new Ray(movement.Position + ((LeftUp+LeftDown) / 2), new Vector3(-1, 0, 0));
            }
            else if (Keyboard.GetState().IsKeyDown(Keys.Right))
            {
                direction.X += 1f;
                XRays[0] = new Ray(movement.Position + RightUp, new Vector3(1, 0, 0));
                XRays[1] = new Ray(movement.Position + RightDown, new Vector3(1, 0, 0));
                XRays[2] = new Ray(movement.Position + ((RightUp + RightDown) / 2), new Vector3(1, 0, 0));
            }
            else
            {
                XRays[0].Direction = Vector3.Zero;
                XRays[1].Direction = Vector3.Zero;
                XRays[2].Direction = Vector3.Zero;
            }

            if (Keyboard.GetState().IsKeyDown(Keys.Up))
            {
                direction.Y += 1f;
                YRays[0] = new Ray(movement.Position + RightUp, new Vector3(0, 1, 0));
                YRays[1] = new Ray(movement.Position + LeftUp, new Vector3(0, 1, 0));
                YRays[2] = new Ray(movement.Position + ((RightUp + LeftUp) / 2), new Vector3(0, 1, 0));
                YRays[3].Direction = Vector3.Zero;
                YRays[4].Direction = Vector3.Zero;
            }
            else if (Keyboard.GetState().IsKeyDown(Keys.Down))
            {
                direction.Y -= 1f;
                YRays[0] = new Ray(movement.Position + RightDown, new Vector3(0, 1, 0));
                YRays[1] = new Ray(movement.Position + LeftDown, new Vector3(0, 1, 0));
                YRays[2] = new Ray(movement.Position + ((RightDown + LeftDown) / 2), new Vector3(0, 1, 0));
                YRays[3] = new Ray(movement.Position + RightDown, new Vector3(0, -1, 0));
                YRays[4] = new Ray(movement.Position + LeftDown, new Vector3(0, -1, 0));
            }
            else
            {
                YRays[0] = new Ray(movement.Position + RightUp, new Vector3(0, 1, 0));
                YRays[1] = new Ray(movement.Position + LeftUp, new Vector3(0, 1, 0));
                YRays[2] = new Ray(movement.Position + ((RightUp + LeftUp) / 2), new Vector3(0, 1, 0));
                YRays[3].Direction = Vector3.Zero;
                YRays[4].Direction = Vector3.Zero;
            }

            if (direction.Length() > 0f)
            {
                direction.Normalize();
            }

            Vector3 velocity;

            if (acceleration == 0)
            {
                velocity = direction * maxspeed;
            }
            else
            {
                velocity = lastVelocity + direction * acceleration * gameTime.ElapsedGameTime.Milliseconds / 1000;

                if (velocity.Length() > maxspeed)
                {
                    velocity.Normalize();
                    velocity = velocity * maxspeed;
                }
            }

            Vector3 diff = velocity * gameTime.ElapsedGameTime.Milliseconds / 1000;
            Vector3 actualMoving = Vector3.Zero;
            float moveLength = diff.Length();
            foreach (Ray moveRay in XRays)
            {
                if (moveRay.Direction == Vector3.Zero)
                {
                    continue;
                }
                foreach (ICollision collision in blockList)
                {
                    float? intersects = moveRay.Intersects(collision.BoundingBox);
                    if (intersects != null)
                    {
                        if (moveLength > intersects)
                        {
                            moveLength = intersects.Value;
                        }

                        if (intersects < 5f)
                        {
                            moveLength = 0;
                            break;
                        }
                    }
                }
            }
            actualMoving += Vector3.Dot(Vector3.Right, direction) * Vector3.Right * moveLength;

            moveLength = diff.Length();
            for (int i = 0; i < YRays.Length; ++i)
            {
                Ray moveRay = YRays[i];
                if (moveRay.Direction == Vector3.Zero)
                {
                    continue;
                }
                foreach (ICollision collision in blockList)
                {
                    float? intersects = moveRay.Intersects(collision.BoundingBox);
                    if (intersects != null)
                    {
                        if (moveLength > intersects)
                        {
                            moveLength = intersects.Value;
                        }

                        if (intersects < 5f)
                        {
                            if (i < 3)
                            {
                                // 강제로 스크롤 됨
                                moveLength = collision.BoundingBox.Min.Y - moveRay.Position.Y - 5;
                            }
                            else
                            {
                                moveLength = 0;
                            }
                            break;
                        }
                    }
                }
            }
            if (moveLength < 0)
            {
                actualMoving += new Vector3(0, moveLength, 0);
            }
            else
            {
                actualMoving += Vector3.Dot(Vector3.Up, direction) * Vector3.Up * moveLength;
            }


            Vector3 newPosition = movement.Position + actualMoving; // direction* moveLength;

            if (moveLength < 0 && newPosition.Y < -400 + 30)
            {
                newPosition.Y = 0;
                newPosition.X = 0;
            }
            else
            {
                newPosition.Y = MathHelper.Min(900, newPosition.Y);
                newPosition.Y = MathHelper.Max(-350, newPosition.Y);
                newPosition.X = MathHelper.Min(400 - 30, newPosition.X);
                newPosition.X = MathHelper.Max(-400 + 30, newPosition.X);
            }
            
            lastVelocity = velocity;
            movement.Position = newPosition;

            if (Keyboard.GetState().IsKeyDown(Keys.LeftControl))
            {
                if (fireButtonUp)
                {
                    FirstWeapon weapon = Owner.FindComponent<FirstWeapon>();

                    if (weapon != null)
                    {
                        weapon.Fire();
                    }
                    fireButtonUp = false;
                }
            }
            else
            {
                fireButtonUp = true;
            }
        }
    }
}
